package LuMin.thread_pool.impl;

import java.util.concurrent.*;

/**
 * @author lumin
 * @date 2022/05/05 19:06
 **/
// 线程池类
public class MyThreadPoolExecutor implements Executor {
    // 创建线程的工厂对象
    private final ThreadFactory threadFactory;

    // 当前正式员工的数量
    private int currentCoreSize;

    // 正式员工的数量上限
    private final int corePoolSize;

    // 当前临时员工的数量
    private int currentTemporarySize;

    // 临时员工的数量上限
    private final int temporaryPoolSize;

    // 传递任务的阻塞队列
    private final BlockingQueue<Runnable> workQueue;

    public MyThreadPoolExecutor(int corePoolSize,
                                int maximumPoolSize,
                                long keepAliveTime,
                                TimeUnit unit,
                                BlockingQueue<Runnable> workQueue,
                                ThreadFactory threadFactory,
                                RejectedExecutionHandler handler) {
        this.corePoolSize = corePoolSize;
        this.temporaryPoolSize = maximumPoolSize - corePoolSize;
        this.workQueue = workQueue;
        this.threadFactory = threadFactory;
    }

    // 向线程池中提交任务
    @Override
    public void execute(Runnable command) {
        // 1. 如果正式员工的数量还低于正式员工的数量上限，则优先创建正式员工处理任务
        // 1.1 需要管理，当前正式员工有多少，正式员工的数量上限有多少？
        if (currentCoreSize < corePoolSize) {
            // 优先创建正式员工进行处理
            // 创建一个线程，这个线程中的任务就是不断地取任务-做任务，但是不需要考虑退出的问题
            CoreJob job = new CoreJob(workQueue, command);
//            Thread thread = new Thread(job);    // 不使用工厂创建的线程
            Thread thread = threadFactory.newThread(job);
            thread.start();

            // 只是两种不同的策略，没有谁是正确的说法
            // 1. 把 command 放到队列中；command 的执行次序是在队列已有的任务之后
            // 2. 创建正式员工的时候，就把 command 提交给正式员工，让 command 优先执行
            // 我们这里采用第二种方案，主要原因就是 java 官方的就是使用的第二种策略

            currentCoreSize++;
            return;
        }

        // 走到这里，说明正式员工的数量 == 正式员工的上限了
        // 2. 优先把任务放入队列中，如果放入成功，execute 执行结束，否则还需要继续
        // 2.1 需要一个阻塞队列
//        workQueue.put(command); // 带阻塞的放入，是否满足这里的需求？
        // 我们这里希望的是立即得到结果
        boolean success = workQueue.offer(command);
        if (success == true) {
            // 说明放入队列成功
            return;
        }

        // 队列也已经放满了
        // 3. 继续判断，临时工的数量有没有到上限，如果没有到达，创建新的临时工来处理
        if (currentTemporarySize < temporaryPoolSize) {
            // 创建临时工进行处理
            currentTemporarySize++;
            return;
        }

        // 4. 执行拒绝策略
    }
}
